////////////////////////////////////////////////
// DESCRIPTION:
//    MSHelp2 registration Custom Action
//
// Legal Notices:
//   Copyright (c) 2008, Telliam Consulting, LLC.
//   All rights reserved.
//
//   Redistribution and use in source and binary forms, with or without modification,
//   are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice, this list
//     of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice, this
//     list of conditions and the following disclaimer in the documentation and/or other
//     materials provided with the distribution.
//   * Neither the name of Telliam Consulting nor the names of its contributors may be
//     used to endorse or promote products derived from this software without specific
//     prior written permission.
//
//   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//   SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
//   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
//   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//   DAMAGE. 
//
#include "stdafx.h"
#include "CustomActionHelpers.h"
#include "RegHelp2CA.h"

static const TCHAR* HelpNamespaceQuery = _T("SELECT * FROM `HelpNamespace`");

static const TCHAR* MergeIndexQuery =_T("SELECT `HelpNamespace_Parent` FROM `HelpPlugin`");

static const TCHAR* HelpPlugInQuery = _T("SELECT `NamespaceName`,`HelpNamespace_Parent`,`File_HxT`,`File_HxA`,`File_ParentHxT`")
                                      _T(" FROM `HelpNamespace`,`HelpPlugin`")
                                      _T(" WHERE `HelpNamespace_`=`NamespaceKey`")
                                      _T(" AND `NamespaceName`='%s'");

static const TCHAR* HelpFileToNamespaceQuery = _T("SELECT `NamespaceName`, `HelpFileName`, `LangID`,`File_HxS`")
                                               _T(" FROM `HelpNamespace`,`HelpFile`,`HelpFileToNamespace`")
                                               _T(" WHERE `HelpFile_`=`HelpFileKey`")
                                               _T(" AND `HelpNamespace_`=`NamespaceKey`")
                                               _T(" AND `NamespaceName`='%s'");

using namespace srutil;
using namespace MSHelpServices;
using namespace FusionWare::MSI;


void RegHelp2CASession::AddNamespace(Record& NamespaceRecord)
{
    CString query;
    CString caData;

    CString nameSpace, collection, description;
    NamespaceRecord.GetField(2, nameSpace);
    NamespaceRecord.GetField(3, collection);
    NamespaceRecord.GetField(4, description);

    CPath collectionPath = this->GetFileInstallPath(collection);
    caData.Format(_T("%s,%s,%s"), nameSpace, collectionPath, description);
    if(!this->NamespaceList.IsEmpty())
        this->NamespaceList.AppendChar(_T(';'));

    this->NamespaceList.Append(caData);

    // Add each help file that belongs to this namespace
    std::auto_ptr<View> view = this->CreateAndExecuteView(HelpFileToNamespaceQuery, nameSpace);
    view->ForEachRecord(GetRecordHandler<&RegHelp2CASession::AddHelpFile>());

    // plugin the namespace if it's listed in the HelpPlugin table
    view = this->CreateAndExecuteView( HelpPlugInQuery, nameSpace );
    view->ForEachRecord(GetRecordHandler<&RegHelp2CASession::AddHelpPlugIn>());
}                                                                                         

void RegHelp2CASession::AddHelpFile(Record& HelpFileRecord)
{
    CString nameSpace,id,fileName;
    int langID;
    CString caData;

    HelpFileRecord.GetField(1, nameSpace);
    HelpFileRecord.GetField(2, id);
    HelpFileRecord.GetField(3, langID);
    HelpFileRecord.GetField(4, fileName);
    
    CPath fullPath = GetFileInstallPath(fileName);
    caData.Format(_T("%s,%s,%d,%s"), nameSpace, id, langID, fullPath);
    if(!this->HelpFileList.IsEmpty())
        this->HelpFileList.AppendChar(_T(';'));

    this->HelpFileList.Append(caData);
}

void RegHelp2CASession::AddHelpPlugIn(Record& PlugInRecord)
{
    CString caData;
    CString ProductNamespace, ProductHxt,Namespace, Hxt, Hxa;
    
    PlugInRecord.GetField(1, Namespace);
    PlugInRecord.GetField(2, ProductNamespace);
    PlugInRecord.GetField(3, Hxt);
    PlugInRecord.GetField(4, Hxa);
    PlugInRecord.GetField(5, ProductHxt);
    
    caData.Format(_T("%s,%s,%s,%s,%s"), ProductNamespace, ProductHxt, Namespace, Hxt, Hxa);
    if(!this->PlugInList.IsEmpty())
        this->PlugInList.AppendChar(_T(','));
    
    this->PlugInList.Append(caData);
}


void RegHelp2CASession::AddMergeIndex(Record& MergeRecord)
{
    CString nameSpace;
    MergeRecord.GetField(1, nameSpace);
    if(!this->MergeList.IsEmpty())
        this->MergeList.AppendChar(_T(';'));

    this->MergeList.Append(nameSpace);
}

void RegHelp2CASession::ContinueTransaction(CString LogPath, bool DeleteOnClose)
{
    CALogFile logFile;

    logFile.Open( CPath( LogPath ), false );
    CString txID = logFile.Read();

    LogMsg(_T("Continuing MSHelp transaction \"%s\""), (LPCTSTR)txID);

    this->HelpSession.ContinueTransaction(txID);
}


void RegHelp2CASession::CreateActionData()
{
    // build up the delimited string lists for the namespaces, help files and plug-ins
    std::auto_ptr<View> view = this->CreateAndExecuteView(HelpNamespaceQuery);
    view->ForEachRecord( GetRecordHandler<&RegHelp2CASession::AddNamespace>() );

    // create the merge index list
    //view = this->CreateAndExecuteView(MergeIndexQuery);
    //view->ForEachRecord(GetRecordHandler<&RegHelp2CASession::AddMergeIndex>());
    // for now just force the VS 9 Combined collection merge
    this->MergeList.Append(_T("MS.VSCC.v90"));
}

// Group = Immediate Custom Action Handlers

void RegHelp2CASession::RegisterHelp()
{
    CString logPath = CreateCustomActionLogName(LogActionInstall, LogTypeRollBack, false);

    CreateActionData();

    ScheduleDeferredAction(_T("MsHelp2StartTransaction"), logPath);
    ScheduleDeferredAction(_T("MsHelp2RegisterNamespaces"), this->NamespaceList);    
    ScheduleDeferredAction(_T("MsHelp2RegisterHelpFiles"), this->HelpFileList);
    ScheduleDeferredAction(_T("MsHelp2PlugInHelpCollections"), this->PlugInList);
    ScheduleDeferredAction(_T("MsHelp2RollbackTransaction"), logPath);
    ScheduleDeferredAction(_T("MsHelp2CommitTransaction"), logPath);
    ScheduleDeferredAction(_T("MsHelp2MergeIndices"), this->MergeList);
}


void RegHelp2CASession::UnregisterHelp( )
{
    CString logPath = CreateCustomActionLogName(LogActionUninstall, LogTypeRollBack, false);

    CreateActionData();

    ScheduleDeferredAction(_T("MsHelp2StartTransaction"), logPath);
    ScheduleDeferredAction(_T("MsHelp2UnplugHelpCollections"), this->PlugInList);
    ScheduleDeferredAction(_T("MsHelp2UnregisterHelpFiles"), this->HelpFileList);
    ScheduleDeferredAction(_T("MsHelp2UnregisterNamespaces"), this->NamespaceList); 
    ScheduleDeferredAction(_T("MsHelp2RollbackTransaction"), logPath);
    ScheduleDeferredAction(_T("MsHelp2CommitTransaction"), logPath);
    ScheduleDeferredAction(_T("MsHelp2MergeIndices"), this->MergeList);
}


// Group = Deffered Custom Action handlers

// CADATA = Path for log file
void RegHelp2CASession::StartTransaction( )
{
    std::vector<CString> args = this->GetCustomActionData(1);

    CALogFile logFile;
    LogMsg(_T("CA Log File: %s"), args[0]);

    logFile.Create( CPath( args[0] ) );
    CString txID = this->HelpSession.CreateTransaction();
    LogMsg(_T("Created MSHelp2 transaction \"%s\""), (LPCTSTR)txID);
    logFile.Write(txID);

    // postpone the transaction for continuation later
    // otherwise ContinueTransaction won't work.
    // It appears to auto revert unless postponed or committed.
    this->HelpSession.PostPoneTransaction();
}

// CADATA = Namespace record list:
// <Namespace,Collection,Description>[;<Namespace,Collection,Description>]...
void RegHelp2CASession::RegisterNamespaces()
{
    ContinueTransaction(LogActionInstall);
   
    std::vector<CString> args = this->GetCustomActionData();
    for(unsigned int i=0; i < args.size(); ++i)
    {
        std::vector<CString> fields = SplitString(args[i], _T(","));
        this->HelpSession.RegisterNamespace(fields[0], fields[1], fields[2]);
    }

    this->HelpSession.PostPoneTransaction();
}

//CADATA = <Namespace,Id,LangID,FileName>[;<Namespace,Id,LangID,FileName>]...
void RegHelp2CASession::RegisterHelpFiles()
{
    ContinueTransaction(LogActionInstall);
    
    std::vector<CString> args = this->GetCustomActionData();
    for(unsigned int i=0; i< args.size(); ++i)
    {
        std::vector<CString> fields = SplitString(args[i], _T(","));
        this->HelpSession.RegisterHelpFile(fields[0], fields[1], _ttoi(fields[2]), fields[3]);
    }

    this->HelpSession.PostPoneTransaction();
}

//CADATA =  <ProductNamespace,ProductHxt,Namespace,Hxt,Hxa>[;<ProductNamespace,ProductHxt,Namespace,Hxt,Hxa>]...
void RegHelp2CASession::PluginHelpCollections()
{
    ContinueTransaction(LogActionInstall);
    
    std::vector<CString> args = this->GetCustomActionData();
    for(unsigned int i=0; i< args.size(); ++i)
    {
        std::vector<CString> fields = SplitString(args[i], _T(","));
        if(fields[1].IsEmpty())
            fields[1] = "_DEFAULT";

        if(fields[3].IsEmpty())
            fields[3] = "_DEFAULT";

        this->HelpSession.RegisterHelpPlugIn(fields[0], fields[1], fields[2], fields[3], fields[4]);
    }

    this->HelpSession.PostPoneTransaction();
}

void RegHelp2CASession::UnregisterNamespaces()
{
    ContinueTransaction(LogActionUninstall);
   
    std::vector<CString> args = this->GetCustomActionData();
    for(unsigned int i=0; i< args.size(); ++i)
    {
        std::vector<CString> fields = SplitString(args[i], _T(","));
        this->HelpSession.RemoveNamespace(fields[0]);
    }

    this->HelpSession.PostPoneTransaction();
}

void RegHelp2CASession::UnregisterHelpFiles()
{
    ContinueTransaction(LogActionUninstall);
    
    std::vector<CString> args = this->GetCustomActionData();
    for(unsigned int i=0; i< args.size(); ++i)
    {
        std::vector<CString> fields = SplitString(args[i], _T(","));
        this->HelpSession.RemoveHelpFile(fields[0], fields[1], _ttoi(fields[2]));
    }

    this->HelpSession.PostPoneTransaction();
}

void RegHelp2CASession::UnplugHelpCollections()
{
    ContinueTransaction(LogActionUninstall);
    
    std::vector<CString> args = this->GetCustomActionData();
    for(unsigned int i=0; i< args.size(); ++i)
    {
        std::vector<CString> fields = SplitString(args[i], _T(","));
        this->HelpSession.RemoveHelpPlugIn(fields[0], fields[1], fields[2], fields[3], fields[4] );
    }

    this->HelpSession.PostPoneTransaction();
}

void RegHelp2CASession::RollbackTransaction( )
{
    std::vector<CString> args = GetCustomActionData(1);
    ContinueTransaction(args[0]);
    this->HelpSession.RollbackTransaction();
}

void RegHelp2CASession::CommitTransaction( )
{
    std::vector<CString> args = GetCustomActionData(1);
    ContinueTransaction(args[0], true);
    this->HelpSession.CommitTransaction();
    LogMsg(_T("Committed MsHelp2 transaction"));
}

void RegHelp2CASession::MergeIndices()
{
    std::vector<CString> args = this->GetCustomActionData();
    for(unsigned int i=0; i< args.size(); ++i)
        this->HelpSession.MergeIndex( args[i] );
}

